import Cesium, { Cartesian3, GroundPrimitive, MaterialAppearance } from '../../Ces/Cesium'

class WeTyphoonCircleWindPrimitive {
  private dirty: boolean = false
  private circleGeometryPrimitive: GroundPrimitive
  private appearance: MaterialAppearance
  private texture: any//Cesium.Texture
  private canvas: HTMLCanvasElement

  private _position: Cartesian3
  private _radius: number

  private _radius7: string | null | undefined = null
  private _radius10: string | null | undefined = null
  private _radius12: string | null | undefined = null
  public show: boolean = false
  constructor() {

  }

  set radius7(value) {
    if (value !== this._radius7) {
      this._radius7 = value
      this.dirty = true
    }
  }

  get radius7() {
    return this._radius7
  }

  set radius10(value) {
    if (value !== this._radius10) {
      this._radius10 = value
      this.dirty = true
    }
  }

  get radius10() {
    return this._radius10
  }

  set radius12(value) {
    if (value !== this._radius12) {
      this._radius12 = value
      this.dirty = true
    }
  }

  get radius12() {
    return this._radius12
  }

  get radius() {
    return this._radius
  }

  set radius(value) {
    this._radius = value
    this.dirty = true
  }

  get position() {
    return this._position
  }

  set position(value) {
    this._position = value
    this.dirty = true
  }

  rebuild(context) {
    //@ts-ignore
    this.circleGeometryPrimitive = this.circleGeometryPrimitive?.destroy()

    if (this._radius7 === ''
      && this._radius10 === ''
      && this._radius12 === ''
    ) {
      this.show = false
      return
    }
    this.show = true

    const canvas = this.drawCanvas()

    if (!this.texture) {
      this.texture = new Cesium.Texture({
        context,
        source: canvas
      })
    } else {
      this.texture.copyFrom({ source: canvas })
    }

    if (!this.appearance) {
      this.appearance = new Cesium.MaterialAppearance({
        renderState: {
          depthTest: { enabled: true },
          depthMask: true,
          blending: Cesium.BlendingState.ALPHA_BLEND,
          cull: {
            enabled: true,
            face: Cesium.CullFace.BACK,
          },
        },
        translucent: false,
        material: new Cesium.Material({
          fabric: {
            uniforms: {
              image: this.texture,
            },
            source:
              'czm_material czm_getMaterial(czm_materialInput materialInput) { \n' +
              '    czm_material material = czm_getDefaultMaterial(materialInput); \n' +
              '    vec2 st = materialInput.st; \n' +
              '    vec4 color = texture(image, st); \n' +
              '    color = czm_gammaCorrect(color); \n' +
              '    material.diffuse = color.rgb; \n' +
              '    material.alpha = color.a; \n' +
              '    material.shininess = 8.0; \n' + // Sharpen highlight
              '    return material; \n' +
              '} \n',
          },
        }),
      })
    }

    const appearance = this.appearance
    const { position } = this

    const radius = this._radius || this.radius

    this.circleGeometryPrimitive = new Cesium.GroundPrimitive({
      geometryInstances: [
        new Cesium.GeometryInstance({
          geometry: new Cesium.CircleGeometry({
            center: position,
            radius,
          }),
        }),
      ],
      asynchronous: false,
      appearance,
    })
  }

  getTyphoonColor(level: number) {
    let strokeStyle = '#FFE4B5FF'
    let fillStyle = '#FFE4B599'

    if (level === 8 || level === 9) {
      strokeStyle = '#0000FFFF'
      fillStyle = '#0000FF99'
    } else if (level === 10 || level === 11) {
      strokeStyle = '#00FF00FF'
      fillStyle = '#00FF0099'
    } else if (level === 12 || level === 13) {
      strokeStyle = '#FFA500FF'
      fillStyle = '#FFA50099'
    } else if (level === 14 || level === 15) {
      strokeStyle = '#DA70D6FF'
      fillStyle = '#DA70D699'
    } else if (level > 15) {
      strokeStyle = '#FF0000FF'
      fillStyle = '#FF000099'
    }

    return { strokeStyle, fillStyle }
  }

  drawCanvas() {
    const radiusInPixels = 512

    if (!this.canvas) {
      this.canvas = document.createElement('canvas')
      this.canvas.width = 2 * radiusInPixels
      this.canvas.height = 2 * radiusInPixels
    }

    const canvas = this.canvas

    const getR1234 = (str) => {
      const s = str.split(' ')
      return {
        northEast: Number(s[0]),
        southEast: Number(s[1]),
        southWest: Number(s[2]),
        northWest: Number(s[3]),
      }
    }


    const drawA = (drawR, ratio) => {
      ctx.beginPath()
      const face = 100
      const bigStep = face / 4
      const angleStep = (Math.PI * 2) / face

      let angle = 0

      for (let f = 0; f < face + 1; f++) {
        const i = Math.floor(f / (face / 4))
        const ra = ratio[i]
        const x = radiusInPixels + Math.cos(angle) * drawR * ra
        const y = radiusInPixels + Math.sin(Math.PI * 2 - angle) * drawR * ra

        if (f % bigStep === 0) {
          const ra = i === 0 ? ratio[ratio.length - 1] : ratio[i - 1]
          const x = radiusInPixels + Math.cos(angle) * drawR * ra
          const y = radiusInPixels + Math.sin(Math.PI * 2 - angle) * drawR * ra

          ctx.lineTo(x, y)
        }
        ctx.lineTo(x, y)
        angle += angleStep
      }
      ctx.stroke()
      ctx.fill()
      ctx.closePath()
    }

    const lineWidth = 4

    const ctx: any = canvas.getContext('2d')
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    ctx.lineWidth = lineWidth
    ctx.moveTo(radiusInPixels, radiusInPixels)

    const r1 = radiusInPixels - lineWidth - 1
    //  2  1
    //  3  4

    const { fillStyle, strokeStyle } = this.getTyphoonColor(7)
    ctx.fillStyle = fillStyle
    ctx.strokeStyle = strokeStyle

    if (this.radius7) {
      const { northEast, southEast, southWest, northWest } = getR1234(this.radius7)
      const maxR = Math.max(northEast, Math.max(southWest, Math.max(southEast, northWest)))
      this._radius = maxR
      drawA(Math.floor((r1 * maxR) / this._radius), [
        northEast / maxR,
        northWest / maxR,
        southWest / maxR,
        southEast / maxR,
      ])
    }
    if (this.radius10) {
      const { fillStyle, strokeStyle } = this.getTyphoonColor(10)
      ctx.fillStyle = fillStyle
      ctx.strokeStyle = strokeStyle
      const { northEast, southEast, southWest, northWest } = getR1234(this.radius10)
      const maxR = Math.max(northEast, Math.max(southWest, Math.max(southEast, northWest)))
      this._radius = Math.max(maxR, this._radius)
      drawA(Math.floor((r1 * maxR) / this._radius), [
        northEast / maxR,
        northWest / maxR,
        southWest / maxR,
        southEast / maxR,
      ])
    }
    if (this.radius12) {
      const { fillStyle, strokeStyle } = this.getTyphoonColor(12)
      ctx.fillStyle = fillStyle
      ctx.strokeStyle = strokeStyle
      const { northEast, southEast, southWest, northWest } = getR1234(this.radius12)
      const maxR = Math.max(northEast, Math.max(southWest, Math.max(southEast, northWest)))
      this._radius = Math.max(maxR, this._radius)
      drawA(Math.floor((r1 * maxR) / this._radius), [
        northEast / maxR,
        northWest / maxR,
        southWest / maxR,
        southEast / maxR,
      ])
    }

    return canvas
  }

  update(frameState) {
    if (this.dirty) {
      this.dirty = false
      this.rebuild(frameState.context)
    }

    if (!this.show) return
    //@ts-ignore
    this.circleGeometryPrimitive?.update(frameState)
  }

  destroy() {
    this.texture = this.texture?.destroy()
    //@ts-ignore
    this.circleGeometryPrimitive = this.circleGeometryPrimitive?.destroy()
    return Cesium.destroyObject(this)
  }
}

export default WeTyphoonCircleWindPrimitive
